bitkeeper revision 1.1159.187.6 (41a4d15eNLlT3wCGjZ2RZQx7hDushg)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 24 Nov 2004 18:22:22 +0000 (18:22 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Wed, 24 Nov 2004 18:22:22 +0000 (18:22 +0000)
Behave properly with grows-down data segments. Maybe some cleaning up
and merging with Michael Fetterman's patches required. :-)

xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_32/seg_fixup.c

index d9a0414d2ef93f29dc24a2aacd63551598d8ebb7..d90a60c5200d10233c0fa091e266447ea8252598 100644 (file)
@@ -190,16 +190,38 @@ int check_descriptor(unsigned long *d)
     limit++; /* We add one because limit is inclusive. */
     if ( (b & _SEGMENT_G) )
         limit <<= 12;
-    if ( ((base + limit) <= base) || 
-         ((base + limit) > PAGE_OFFSET) )
+
+    if ( (b & (3<<10)) == 1 )
+    {
+        /*
+         * Grows-down limit check. 
+         * NB. limit == 0xFFFFF provides no access      (if G=1).
+         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
+         */
+        if ( (base + limit) > base )
+        {
+            limit = -(base & PAGE_MASK);
+            goto truncate;
+        }
+    }
+    else
     {
-        /* Need to truncate. Calculate and poke a best-effort limit. */
-        limit = PAGE_OFFSET - base;
-        if ( (b & _SEGMENT_G) )
-            limit >>= 12;
-        limit--;
-        d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
-        d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+        /*
+         * Grows-up limit check.
+         * NB. limit == 0xFFFFF provides 4GB access (if G=1).
+         *     limit == 0x00000 provides 4kB access (if G=1).
+         */
+        if ( ((base + limit) <= base) || 
+             ((base + limit) > PAGE_OFFSET) )
+        {
+            limit = PAGE_OFFSET - base;
+        truncate:
+            if ( !(b & _SEGMENT_G) )
+                goto bad; /* too dangerous; too hard to work out... */
+            limit = (limit >> 12) - 1;
+            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
+            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+        }
     }
 
  good:
index dc8e760020ab8c83763b2d0cda865cf4cc97e822..85d7d75def9604b1e26c606ae82a5d6a60bc0dca 100644 (file)
@@ -225,8 +225,7 @@ int fixup_seg(u16 seg, int positive_access)
         if ( ((base + limit) < PAGE_SIZE) && positive_access )
         {
             /* Flip to expands-up. */
-            limit >>= 12;
-            limit -= (-PAGE_OFFSET/PAGE_SIZE) + 2;
+            limit = PAGE_OFFSET - base;
             goto flip;
         }
     }
@@ -236,8 +235,7 @@ int fixup_seg(u16 seg, int positive_access)
         if ( ((PAGE_OFFSET - (base + limit)) < PAGE_SIZE) && !positive_access )
         {
             /* Flip to expands-down. */
-            limit >>= 12;
-            limit += (-PAGE_OFFSET/PAGE_SIZE) + 0;
+            limit = -(base & PAGE_MASK);
             goto flip;
         }
     }
@@ -249,9 +247,10 @@ int fixup_seg(u16 seg, int positive_access)
     return 0;
 
  flip:
+    limit = (limit >> 12) - 1;
     a &= ~0x0ffff; a |= limit & 0x0ffff;
     b &= ~0xf0000; b |= limit & 0xf0000;
-    b ^= 1 << 10;
+    b ^= 1 << 10; /* grows-up <-> grows-down */
     /* NB. These can't fault. Checked readable above; must also be writable. */
     table[2*idx+0] = a;
     table[2*idx+1] = b;